[Windows编程笔记]HASH值的计算 您所在的位置:网站首页 windows 计算哈希 [Windows编程笔记]HASH值的计算

[Windows编程笔记]HASH值的计算

2023-07-11 00:51| 来源: 网络整理| 查看: 265

《Windows黑客编程技术详解》学习笔记

HASH就是把任意长度的输入通过HASH算法变换成固定长度的输出,该输出就是HASH值。

函数介绍 // 用于获取特定加密服务提供程序(CSP)内特定密钥容器的句柄,返回的句柄使用选定CSP的CryptoAPI函数。 BOOL CryptAcquireContextA( HCRYPTPROV *phProv, // 指向CSP句柄的指针。当完成CSP时,通过调用CryptReleaseContext函数释放句柄。 LPCSTR szContainer, // NULL LPCSTR szProvider, // NULL DWORD dwProvType, // PROV_RSA_AES表示支持RSA、AES、HASH算法 DWORD dwFlags // CRYPT_VERIFYCONTEXT表示程序不需要使用公钥/私钥对,例如只执行HASH和对称加密 ); ​ BOOL CryptCreateHash( HCRYPTPROV hProv, // CryptAcquireContextA创建的CSP句柄 ALG_ID Algid, // 要使用的HASH算法,由用户传入 HCRYPTKEY hKey, // NULL DWORD dwFlags, // NULL HCRYPTHASH *phHash // 新哈希对象的地址 ); ​ BOOL CryptHashData( HCRYPTHASH hHash, // CryptCreateHash创建的哈希对象的句柄 const BYTE *pbData, // 指向要计算HASH的数据的指针 DWORD dwDataLen, // 要计算的数据的字节数 DWORD dwFlags // 0 ); ​ BOOL CryptGetHashParam( HCRYPTHASH hHash, // CryptCreateHash创建的哈希对象的句柄 DWORD dwParam, // 查询类型。可以选择查询HASH结果的大小或HASH值 BYTE *pbData, // 指向接收数据的缓冲区的指针 DWORD *pdwDataLen, // pbData的字节数 DWORD dwFlags // 0 );

 

编码实现

代码来自https://www.jb51.net/books/755116.html

// CryptoApi_Hash_Test.cpp : 定义控制台应用程序的入口点。 // ​ #include #include #include ​ ​ void ShowError(char *pszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError()); #ifdef _DEBUG ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR); #endif } ​ ​ BOOL GetFileData(char *pszFilePath, BYTE **ppFileData, DWORD *pdwFileDataLength) { BOOL bRet = TRUE; BYTE *pFileData = NULL; DWORD dwFileDataLength = 0; HANDLE hFile = NULL; DWORD dwTemp = 0; ​ do { hFile = ::CreateFile(pszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { bRet = FALSE; ShowError("CreateFile"); break; } ​ dwFileDataLength = ::GetFileSize(hFile, NULL); ​ pFileData = new BYTE[dwFileDataLength]; if (NULL == pFileData) { bRet = FALSE; ShowError("new"); break; } ::RtlZeroMemory(pFileData, dwFileDataLength); ​ ::ReadFile(hFile, pFileData, dwFileDataLength, &dwTemp, NULL); ​ // 返回 *ppFileData = pFileData; *pdwFileDataLength = dwFileDataLength; ​ } while (FALSE); ​ if (hFile) { ::CloseHandle(hFile); } ​ return bRet; } ​ ​ BOOL CalculateHash(BYTE *pData, DWORD dwDataLength, ALG_ID algHashType, BYTE **ppHashData, DWORD *pdwHashDataLength) { HCRYPTPROV hCryptProv = NULL; HCRYPTHASH hCryptHash = NULL; BYTE *pHashData = NULL; DWORD dwHashDataLength = 0; DWORD dwTemp = 0; BOOL bRet = FALSE; ​ ​ do { // 获得指定CSP的密钥容器的句柄 bRet = ::CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); if (FALSE == bRet) { ShowError("CryptAcquireContext"); break; } ​ // 创建一个HASH对象, 指定HASH算法 bRet = ::CryptCreateHash(hCryptProv, algHashType, NULL, NULL, &hCryptHash); if (FALSE == bRet) { ShowError("CryptCreateHash"); break; } ​ // 计算HASH数据 bRet = ::CryptHashData(hCryptHash, pData, dwDataLength, 0); if (FALSE == bRet) { ShowError("CryptHashData"); break; } ​ // 获取HASH结果的大小 dwTemp = sizeof(dwHashDataLength); bRet = ::CryptGetHashParam(hCryptHash, HP_HASHSIZE, (BYTE *)(&dwHashDataLength), &dwTemp, 0); if (FALSE == bRet) { ShowError("CryptGetHashParam"); break; } ​ // 申请内存 pHashData = new BYTE[dwHashDataLength]; if (NULL == pHashData) { bRet = FALSE; ShowError("new"); break; } ::RtlZeroMemory(pHashData, dwHashDataLength); ​ // 获取HASH结果数据 bRet = ::CryptGetHashParam(hCryptHash, HP_HASHVAL, pHashData, &dwHashDataLength, 0); if (FALSE == bRet) { ShowError("CryptGetHashParam"); break; } ​ // 返回数据 *ppHashData = pHashData; *pdwHashDataLength = dwHashDataLength; ​ } while (FALSE); ​ // 释放关闭 if (FALSE == bRet) { if (pHashData) { delete[]pHashData; pHashData = NULL; } } if (hCryptHash) { ::CryptDestroyHash(hCryptHash); } if (hCryptProv) { ::CryptReleaseContext(hCryptProv, 0); } ​ return bRet; } ​ ​ int _tmain(int argc, _TCHAR* argv[]) { BYTE *pData = NULL; DWORD dwDataLength = 0; DWORD i = 0; BYTE *pHashData = NULL; DWORD dwHashDataLength = 0; ​ // 读取文件数据 GetFileData("C:\\Users\\Administrator\\Desktop\\Project8.exe", &pData, &dwDataLength); ​ // MD5 CalculateHash(pData, dwDataLength, CALG_MD5, &pHashData, &dwHashDataLength); printf("MD5[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } ​ // SHA1 CalculateHash(pData, dwDataLength, CALG_SHA1, &pHashData, &dwHashDataLength); printf("SHA1[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } ​ // SHA256 CalculateHash(pData, dwDataLength, CALG_SHA_256, &pHashData, &dwHashDataLength); printf("SHA256[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } ​ system("pause"); return 0; }

 

实现过程

首先写一个GetFileData函数来获取文件数据,其中用了CreateFile函数来打开文件

HANDLE CreateFileA( LPCSTR lpFileName, // 文件路径和文件名 DWORD dwDesiredAccess, // GENERIC_READ | GENERIC_WRITE表示读写权限 DWORD dwShareMode, // FILE_SHARE_READ | FILE_SHARE_WRITE表示共享读写权限 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // NULL DWORD dwCreationDisposition, // OPEN_EXISTING表示仅当文件存在时打开文件 DWORD dwFlagsAndAttributes, // FILE_ATTRIBUTE_ARCHIVE表示标记要备份或删除的文件 HANDLE hTemplateFile // NULL );

 

然后用GetFileSize函数来获取文件长度

DWORD GetFileSize( HANDLE hFile, // 文件的句柄 LPDWORD lpFileSizeHigh // NULL );

 

然后用ReadFile函数将文件内容读取到新的内存空间

BOOL ReadFile( HANDLE hFile, // 文件句柄 LPVOID lpBuffer, // 指向接收文件内容的缓冲区的指针 DWORD nNumberOfBytesToRead, // 读取的最大字节数 LPDWORD lpNumberOfBytesRead, // 接收读取的字节数 LPOVERLAPPED lpOverlapped // NULL );

 

GetFileData函数返回了文件内容和文件内容长度。

接着写了CalculateHash函数来计算HASH值,整体上就是上面的4个API函数依次用。首先用CryptAcquireContextA函数获取一个指向CSP句柄的指针,然后用CryptCreateHash函数在CSP中创建一个空的HASH对象并获取对象句柄,并可以指定HASH算法,接着使用CryptHashData函数来计算数据的HASH值,结果存放在HASH对象中,最后使用CryptGetHashParam函数来获取想要的数据,可以获取的数据有三种:HASH算法、HASH值长度、HASH值。获取完HASH值后使用CryptReleaseContext函数释放CSP句柄,使用CryptDestroyHash函数来释放HASH对象句柄。

 

 

 

 

小结

计算HASH值的操作步骤主要是创建空HASH对象,然后将数据添加到HASH对象中并计算HASH值。因为有不同的HASH算法,HASH值长度也不同,所以在调用CryptGetHashParam函数获取HASH值之前,应先获取HASH值的大小,以便申请足够的缓冲区。

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有